package Game;

import java.io.IOException;
import java.util.ArrayList;

import Distributive.casinoRoyale;
import cardCollections.Hand;
import cardCollections.Shoe;
import cards.Card;

/**
 * @author CAT
 * 
 */
public class GameClass {

	private Shoe currentShoe;
	private ArrayList<Hand> hands;
	private Dealer dealersHand;
	private int totalPlayers;

	/**
	 * @param Currentshoe
	 *            , the shoe to be used in this game
	 * @param playerHands
	 *            the list of all player hands
	 * @param CurrentDealer
	 *            the dealer to be used
	 * @param numPlayers
	 *            the total number of players
	 * @throws IOException
	 *             if currentShoe is unable to find the necessary image files
	 */
	public GameClass(Shoe Currentshoe, ArrayList<Hand> playerHands,
			Dealer CurrentDealer, int numPlayers) throws IOException {
		currentShoe = Currentshoe;
		hands = playerHands;
		dealersHand = CurrentDealer;
		currentShoe.restoreDeck();
		totalPlayers = numPlayers;
	}

	/**
	 * @param numPlayers
	 *            the total number of players
	 * @throws IOException
	 *             if currentShoe is unable to find the necessary image files
	 */
	public GameClass(int numPlayers) throws IOException {
		currentShoe = new Shoe();
		hands = new ArrayList<Hand>();
		hands.add(new Hand());
		hands.add(new Hand());
		dealersHand = new Dealer();
		totalPlayers = numPlayers;
		currentShoe.restoreDeck();

	}

	/**
	 * @param handIndex
	 *            , the index of the players hand in hands
	 * @throws IOException
	 *             if the current shoe is unable to find the image file for the
	 *             card
	 */
	public void hit(int handIndex) throws IOException {
		hands.get(handIndex).AddCard(currentShoe.dealCard());
	}

	/**
	 * @throws IOException
	 *             if the current shoe is unable to find the image file for the
	 *             card game logic for the dealer. The dealer hits if
	 *             dealer.getHandCount < 17, else the dealer stands
	 */
	public void dealer() throws IOException {
		if (dealersHand.dealerHit())
			dealersHand.AddCard(currentShoe.dealCard());
		else
			dealersHand.setStandValue(true);
	}

	/**
	 * @param handIndex
	 *            , the index of the players hand in Hands
	 * @return 1 if the player lost, 0 if hte player tied, -1 if the player won
	 *         Checks if the player busted. If so, it resets the hand and
	 *         returns 1 Then checks if the dealer busted. If so, it resets the
	 *         hand and returns -1 Then checks if the players handCount is less
	 *         than dealers handCount. If so, resets the hand and returns 1 Then
	 *         checks if the players handCount equals the dealers handCount. If
	 *         so, resets the hand and returns 0 else it resets the hand and
	 *         returns -1
	 */
	public int checkWin(int handIndex) {
		if (hands.get(handIndex).isBusted()) {
			this.reset(handIndex);
			return 1;
		} else if (dealersHand.isBusted()) {
			this.reset(handIndex);
			return -1;
		} else if (hands.get(handIndex).getHandCount() < dealersHand
				.getHandCount()) {
			this.reset(handIndex);
			return 1;
		} else if (hands.get(handIndex).getHandCount() == dealersHand
				.getHandCount()) {
			this.reset(handIndex);
			return 0;
		} else {
			this.reset(handIndex);
			return -1;
		}

	}

	/**
	 * @param handIndex
	 *            , the index of the players hand in this.hands sets
	 *            theStandValue of the player to true
	 */
	public void stand(int handIndex) {
		hands.get(handIndex).setStandValue(true);
	}

	/**
	 * @param handIndex
	 *            the index of the players hand in this.hands calls
	 *            hand.resetHand on the players Hand
	 */
	private void reset(int handIndex) {
		hands.get(handIndex).resetHand();
	}

	/**
	 * @param handIndex
	 *            the index of the players hand in this.hands
	 * @throws IOException
	 *             if the currentShoe cannot find the appropriate image files
	 *             makes a new temporary hand and adds it to current hand, adds
	 *             an aditional card to it. Then it adds an additional card the
	 *             current players main hand Note, this method is not used in
	 *             the current implementation because it causes awkward errors
	 */
	public void splitHand(int handIndex) throws IOException {
		Hand tempHand = new Hand();
		tempHand.AddCard(hands.get(handIndex).removeCard());
		hands.add(tempHand);
		hands.get(handIndex).AddCard(currentShoe.dealCard());
		hands.get(hands.size() - 1).AddCard(currentShoe.dealCard());

	}

	/**
	 * @param handIndex
	 *            the index of the players hand in this.hands
	 * @throws IOException
	 *             if the currentShoe cannot find the appropriate image files
	 *             sets the players hand to standing and deals one additional
	 *             card Note, this method is not used in the current
	 *             implementation because it is only for use when betting
	 */
	public void Doubledown(int handIndex) throws IOException {
		hands.get(handIndex).setStandValue(true);
		hit(handIndex);
	}

	/**
	 * sets this.hands to a new ArrayList<Hand> re-populates hands with
	 * this.totalPlayers hands sets this.dealersHand to a new Dealer
	 */
	public void newRound() {
		hands = new ArrayList<Hand>();
		for (int i = 0; i < totalPlayers; i++) {
			hands.add(new Hand());
		}
		dealersHand = new Dealer();
	}

	/**
	 * @return the total number of players
	 */
	public int getTotalPlayers() {
		return this.totalPlayers;
	}

	/**
	 * @return the total number of hands Only actually useful when splitting
	 *         hands
	 */
	public int getHandSize() {
		return this.hands.size();
	}

	/**
	 * @param handIndex
	 *            the index of the players hand in this.hands
	 * @return returns the hand at this.hands[handIndex]
	 */
	public Hand getHand(int handIndex) {
		return this.hands.get(handIndex);
	}

	/**
	 * @return true if all players are either standing or busted checks if any
	 *         players are neither standing nor busted. If so, returns false
	 *         Then checks if the player is neither standing nor busted. If so,
	 *         returns false Else returns true
	 */
	public boolean isEveryoneDone() {

		for (Hand player : hands) {
			if (!player.isBusted() && !player.isStanding())
				return false;
		}
		if (!dealersHand.isStanding() && !dealersHand.isBusted()) {
			return false;
		}
		return true;

	}

	/**
	 * @throws IOException
	 *             if currentShoe is not able to find the appropriate image
	 *             files calls a new round, then one card each to each player
	 *             and the dealer twice
	 */
	public void deal() throws IOException {
		this.newRound();
		for (Hand h : hands) {
			h.AddCard(currentShoe.dealCard());
		}
		dealersHand.AddCard(currentShoe.dealCard());
		for (Hand h : hands) {
			h.AddCard(currentShoe.dealCard());
		}
		dealersHand.AddCard(currentShoe.dealCard());
	}

	/**
	 * @return the dealers hand
	 */
	public Hand getDealerHand() {
		return (this.dealersHand);

	}

	/**
	 * @return all the players hands
	 */
	public ArrayList<Hand> getHands() {
		return this.hands;
	}

	/**
	 * @return a list of all current cards in all hands including the dealers
	 */
	public ArrayList<String> getCardStringToWrite() {
		ArrayList<String> retList = new ArrayList<String>();
		for (int i = 0; i < hands.size(); i++) {
			retList.add("Player " + (i+1) + " hand: " + hands.get(i).getPlayerHand().toString()+"\t");
		}
		retList.add("Dealer hand: " + dealersHand.getPlayerHand().toString());
		retList.add("\n");
		return retList;

	}

}
